<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }


        #Buts {
            position: absolute;
            top: 0;
        }
    </style>
</head>

<body>

    <canvas id="canvas">

    </canvas>
    <div id="Buts">
        <button id="former">正</button>
        <button id="top">顶</button>
        <button id="left">侧</button>
    </div>
</body>

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform mat4 u_PvM4;
    uniform mat4 u_ModelM4;
    uniform float u_PointSize;
    void main(){
        gl_Position = u_PvM4 * u_ModelM4 * a_Position;
        gl_PointSize = u_PointSize;
    }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
    precision mediump float;
    uniform vec4 u_Color;
    void main(){
        if(distance(gl_PointCoord,vec2(0.5,0.5)) < 0.5)
        {
            gl_FragColor = u_Color;
        }
    }
</script>
<script type="module">
    //#region 
    import { Matrix4, Vector2, Vector3, Color, PerspectiveCamera, Quaternion, Spherical } from '../js/three.module.js';
    import Poly from '../js/Poly3.js';
    import { initShaders } from '../js/Utils.js';
    import lib from '../js/ThreeLib.js';
    //#endregion

    //#region gl
    const canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight - 4;

    const gl = canvas.getContext("webgl");
    //开始背景遮挡
    // gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

    initShaders(gl,
        document.querySelector("#vertexShader").innerText,
        document.querySelector("#fragmentShader").innerText);
    lib.clearCanvas(gl, new Color("rgba(0,0,0,1)"), 1);
    //#endregion

    //#region 创建相机
    const [fov, aspect, near, far] = [
        45, //摄像机的弧度
        canvas.width / canvas.height,   //投影的宽高比
        1,  //投影窗口的最小z值
        20  //投影窗口的最大z值
    ];
    const camera = new PerspectiveCamera(fov, aspect, near, far);
    //#endregion

    const eye = new Vector3(0, 0.5, 3);//相机位置
    const lookAt = new Vector3(0, 0, 0);//看向的位置
    const zoomScale = 0.05;//缩放系数
    const length = 99;//坐标长度

    const pvM4 = getPvM4(eye, lookAt);

    const mouseButtons = new Map([
        [0, 'left'],
        [2, 'right'],
    ]);
    //鼠标位移的偏转量
    const [dragCur, dragLast] = [
        new Vector2(),
        new Vector2()
    ];
    const spherical = new Spherical()
        .setFromVector3(
            camera.position.clone().sub(lookAt)
        );
    const spherical1 = new Spherical(camera.position.clone().sub(lookAt).length());

    console.log(spherical)
    console.log(spherical1)

    //用于旋转的四元数
    const quaternion = new Quaternion();
    //状态
    let state = 'none';

    const polyArr = [];


    //Main
    (function main() {

        let poly1 = create(
            [1, 0, 0, 1],
            new Matrix4().setPosition(-0.5, 0, -3)
        );
        let poly2 = create(
            [0, 1, 0, 1],
            new Matrix4().setPosition(0.5, 0, -3)
        );
        let poly3 = create(
            [0, 0, 1, 1],
            new Matrix4().setPosition(-0.5, 0, -2)
        );
        let poly4 = create(
            [1, 1, 1, 1],
            new Matrix4().setPosition(0.5, 0, -2)
        );

        //世界坐标轴
        let poly5 = new Poly({
            gl: gl,
            arr: [
                0, -length, 0,
                0, length, 0,
                length, 0, 0,
                -length, 0, 0,
                0, 0, length,
                0, 0, -length
            ],
            list: [
                { name: 'a_Position', size: 3, beginIndex: 0 }
            ],
            uniforms: {
                'u_Color': {
                    type: 'uniform4fv',
                    value: [1, 1, 1, 1]
                },
                'u_PvM4': {
                    type: 'uniformMatrix4fv',
                    value: pvM4.elements
                },
                'u_ModelM4': {
                    type: 'uniformMatrix4fv',
                    value: new Matrix4().elements
                },
            }
        });

        //视点
        let poly6 = new Poly({
            gl: gl,
            arr: [
                lookAt.x,
                lookAt.y,
                lookAt.z,
            ],
            list: [
                { name: 'a_Position', size: 3, beginIndex: 0 }
            ],
            uniforms: {
                'u_Color': {
                    type: 'uniform4fv',
                    value: [0.5, 0.5, 0.5, 1]
                },
                'u_PvM4': {
                    type: 'uniformMatrix4fv',
                    value: pvM4.elements
                },
                'u_ModelM4': {
                    type: 'uniformMatrix4fv',
                    value: new Matrix4().elements
                },
                'u_PointSize': {
                    type: 'uniform1f',
                    value: 5
                }
            }
        });

        polyArr.push(
            [['TRIANGLES'], poly1],
            [['TRIANGLES'], poly2],
            [['TRIANGLES'], poly3],
            [['TRIANGLES'], poly4],
            [['LINES'], poly5],
            [['POINTS'], poly6],
        )

        rend();
    })();




    canvas.addEventListener('contextmenu', (event) => {
        event.preventDefault();
    });
    canvas.addEventListener('pointerdown', (event) => {
        dragCur.set(event.clientX, event.clientY);
        dragLast.copy(dragCur);
        state = mouseButtons.get(event.button);
    });
    canvas.addEventListener('pointermove', ({ clientX, clientY }) => {
        dragCur.set(clientX, clientY)
        switch (state) {
            case 'right':
                cameraPosition(dragCur.clone().sub(dragLast))
                break;
            case 'left':
                cameraRotation(dragCur.clone().sub(dragLast));
                break;
        }
        dragLast.copy(dragCur);

    });
    canvas.addEventListener('pointerup', (event) => {
        state = 'none';
        // console.log(camera.rotation)
    });
    canvas.addEventListener('wheel', function ({ deltaY }) {
        cameraZoom(deltaY);
    })

    //#region 旋转
    function cameraRotation(moveDiff) {
        const { fov, matrix, position } = camera;
        const { clientWidth, clientHeight } = canvas;

        const jl = eye.distanceTo(lookAt);

        //相机的宽高
        const cameraH = Math.tan(fov / 2) * jl * 2;
        const cameraW = aspect * cameraH;

        //计算视图偏移量
        const ratioX = moveDiff.x / clientWidth;
        const ratioY = -moveDiff.y / clientHeight;

        const ratioXBaseHeight = moveDiff.x / clientHeight;
        //位移量
        const ratioLen = new Vector2(ratioXBaseHeight, ratioY).length();
        //旋转量
        const angle = ratioLen * Math.PI * 2;

        //在相机世界中的位移距离
        const distanceLeft = ratioX * cameraW;
        const distanceUp = ratioY * cameraH;

        // 相机本地坐标系的x,y轴
        const mx = new Vector3().setFromMatrixColumn(camera.matrix, 0);
        const my = new Vector3().setFromMatrixColumn(camera.matrix, 1);

        // 将鼠标在相机世界的x,y轴向的位移量转换为世界坐标位
        const vx = mx.clone().multiplyScalar(distanceLeft);
        const vy = my.clone().multiplyScalar(distanceUp);

        //鼠标在世界坐标系中的位移方向-x轴
        const moveDir = vx.clone().add(vy).normalize();

        //目标点到视点的单位向量-z轴
        const eyeDir = camera.position.clone().sub(lookAt).normalize();


        //基于位移方向和视线获取旋转轴-上方向y轴
        const axis = moveDir.clone().cross(eyeDir);
        quaternion.setFromAxisAngle(axis, angle);

        updateRotation(quaternion);

    }

    function updateRotation(quaternion) {
        const rotateOffset = camera.position.clone()
            .sub(lookAt)
            .applyQuaternion(quaternion)

        camera.position.copy(
            eye.copy(lookAt.clone().add(rotateOffset))
        )

        camera.up.applyQuaternion(quaternion)
        camera.lookAt(lookAt);
        camera.updateMatrixWorld(true)
        pvM4.multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse,
        )

        rend();


    }
    //#endregion 

    //#region 移动
    function cameraPosition(moveDiff) {

        //两点的距离
        let len = eye.distanceTo(lookAt);
        //获取摄像机弧度的一半
        let halfFov = fov * Math.PI / 360;
        //获取视点的高度
        let sh = len * Math.tan(halfFov) * 2;
        //获取视点的宽度
        let sw = aspect * sh;

        let x = moveDiff.x * sw / canvas.clientWidth;
        let y = moveDiff.y * sh / canvas.clientHeight;
        // updatePosition(new Vector3(-x, y, 0));//这个是基于世界坐标移动

        //因为Z轴不知道,所以需要进行分开相乘

        //获取相机本地坐标系中的X列
        const cameraX = new Vector3().setFromMatrixColumn(camera.matrix, 0)
        const myOrz = new Vector3();

        // //根据上方向与X轴进行叉乘,获取-z轴
        //myOrz.crossVectors(camera.up, cameraX);

        //获取相机的Y轴
        myOrz.setFromMatrixColumn(camera.matrix, 1);

        const vx = cameraX.clone().multiplyScalar(-x);
        const vy = myOrz.clone().multiplyScalar(y);

        updatePosition(vx.add(vy));
    }

    function updatePosition(vec3) {
        camera.position.copy(eye.add(vec3));
        camera.lookAt(lookAt.add(vec3));
        camera.updateMatrixWorld(true);
        pvM4.multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse
        );
        rend();
    }
    //#endregion

    //#region 缩放
    function cameraZoom(zoomDiff) {
        //#region lerp缩放
        // if (zoomDiff < 0) {
        //     updateZoom(zoomScale);
        // } else {
        //     updateZoom(-zoomScale);
        // }
        //#endregion

        //#region 球坐标缩放
        if (zoomDiff < 0) {
            updateZoom(1 - zoomScale);
        } else {
            updateZoom(1 + zoomScale);
        }
        //#endregion

    }

    function updateZoom(scale) {
        //#region lerp缩放
        // camera.position.copy(eye.lerp(lookAt, scale));
        // camera.lookAt(lookAt);
        // camera.updateWorldMatrix(true);
        //#endregion

        //#region 球坐标缩放
        spherical.setFromVector3(camera.position.clone().sub(lookAt));
        spherical.radius *= scale;

        const rotateOffset = new Vector3().setFromSpherical(spherical);
        camera.position.copy(eye.copy(lookAt.clone().add(rotateOffset)));
        camera.lookAt(lookAt);
        camera.updateWorldMatrix(true);
        //#endregion

        pvM4.multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse
        );

        rend();
    }
    //#endregion


    function getPvM4(eye, lookAt) {
        camera.position.copy(eye);
        camera.lookAt(lookAt);
        camera.updateMatrixWorld(true);
        return new Matrix4().multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse
        );
    }

    //创建Poly
    function create(color, modelM4) {
        // poly.draw(["TRIANGLES", "POINTS"]);
        return new Poly({
            gl: gl,
            arr: [
                0, 0.3, 0,
                0.3, -0.3, 0,
                -0.3, -0.3, 0
            ],
            list: [
                { name: 'a_Position', size: 3, beginIndex: 0 }
            ],
            uniforms: {
                'u_Color': {
                    type: 'uniform4fv',
                    value: color
                },
                'u_PvM4': {
                    type: 'uniformMatrix4fv',
                    value: pvM4.elements
                },
                'u_ModelM4': {
                    type: 'uniformMatrix4fv',
                    value: modelM4.elements
                },
            }
        });
    }

    //渲染
    function rend() {
        lib.clearCanvas(gl, new Color("rgba(0,0,0,1)"), 1);
        polyArr[5][1].arr = [lookAt.x, lookAt.y, lookAt.z];
        polyArr[5][1].updateAttribute();
        polyArr.forEach(u => {
            u[1].init();
            u[1].draw(u[0]);
        });
    }

    //#region button 有问题
    document.getElementById('former').addEventListener('click', function () {

    })
    //#endregion

</script>

</html>